#!/usr/bin/python3
# -*- coding:utf-8 -*-
# __author__ = '__Jack__'
import os

from sqlalchemy import create_engine
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import sessionmaker
from config.config import CFG
from log import log
from urllib.parse import quote_plus as urlquote
from sqlalchemy import event


cfg = CFG().cfg
db_conf = cfg.db
if CFG.env != 'prod':
    log.info(f"database.py: {cfg}")
    print(db_conf.type, db_conf.server, db_conf.username, db_conf.password)

echo_enable = True if CFG.env != 'prod' else False

if db_conf.type == "mssql":
    log.info('mssql is running!')
    DATABASE_URL = f'mssql+pymssql://{db_conf.username}:{urlquote(db_conf.password)}@{db_conf.server}/{db_conf.database}?charset=utf8'
    log.info(DATABASE_URL)
    engine = create_engine(f'mssql+pymssql://{db_conf.username}:{urlquote(db_conf.password)}@{db_conf.server}/{db_conf.database}?charset=utf8', echo=echo_enable)
elif db_conf.type == "mysql":
    log.info('mysql is running!')
    DATABASE_URL = f'mysql+pymysql://{db_conf.username}:{urlquote(db_conf.password)}@{db_conf.server}/{db_conf.database}?charset=utf8'
    engine = create_engine(DATABASE_URL, echo=echo_enable)
elif "pg" in db_conf.type:
    log.info('postgresql is running!')
    DATABASE_URL = f"postgresql://{db_conf.username}:{urlquote(db_conf.password)}@{db_conf.server}/{db_conf.database}"
    log.info(DATABASE_URL)
    engine = create_async_engine(DATABASE_URL, echo=echo_enable, future=True)
else:
    if not os.path.exists("sqlite"):  # 如果目录不存在，则创建目录
       os.makedirs("sqlite")
    DATABASE_URL = f'sqlite:///./sqlite/{db_conf.database}.sqlite3'
    engine = create_engine(
        # echo=True表示引擎将用repr()函数记录所有语句及其参数列表到日志
        # 由于SQLAlchemy是多线程，指定check_same_thread=False来让建立的对象任意线程都可使用。这个参数只在用SQLite数据库时设置
        DATABASE_URL, echo=True, connect_args={'check_same_thread': False}
    )
# SQLALCHEMY_DATABASE_URL = "postgresql://username:password@host:port/database_name"  # MySQL或PostgreSQL的连接方法
# 在SQLAlchemy中，CRUD都是通过会话(session)进行的，所以我们必须要先创建会话，每一个SessionLocal实例就是一个数据库session
# flush()是指发送数据库语句到数据库，但数据库不一定执行写入磁盘；commit()是指提交事务，将变更保存到数据库文件
# 当autoflush设置为False时，会话在执行查询之前不会自动刷新挂起的更改。这意味着挂起的更改不会被写入数据库，直到你显式调用flush()或commit()! False 这种设置可以提高性能，特别是在你不需要立即刷新更改的情况下

class SqlBase(DeclarativeBase):
    pass



if "asyncpg" in DATABASE_URL:
    engine = create_async_engine(DATABASE_URL, echo=echo_enable, future=True)
    SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine, class_=AsyncSession)
    async def get_db():
        async with SessionLocal() as session:
            yield session

else:
    engine = create_engine(DATABASE_URL, echo=echo_enable)
    SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine, expire_on_commit=True)
    # SessionLocal = sessionmaker(bind=engine, autoflush=True, autocommit=False, expire_on_commit=True)
    def get_db():
        db = SessionLocal()
        try:
            yield db
        finally:
            db.close()



def init_db(app):
    if "asyncpg" in DATABASE_URL:
        @app.on_event("startup")
        async def startup():
            async with engine.begin() as conn:
                await conn.run_sync(SqlBase.metadata.create_all)
    else:
        @app.on_event("startup")
        def startup():
            SqlBase.metadata.create_all(bind=engine)



